package com.jiangjiang.eshop.order.biz;

import com.jiangjiang.eshop.common.constant.PromotionActivityType;
import com.jiangjiang.eshop.customer.service.CustomerFacadeService;
import com.jiangjiang.eshop.inventory.service.InventoryService;
import com.jiangjiang.eshop.order.constant.OrderStatus;
import com.jiangjiang.eshop.order.constant.PublishedComment;
import com.jiangjiang.eshop.order.dto.*;
import com.jiangjiang.eshop.order.price.v1.calculator.CouponCalculator;
import com.jiangjiang.eshop.order.price.v1.calculator.FreightCalculator;
import com.jiangjiang.eshop.order.price.v1.calculator.PromotionActivityCalculator;
import com.jiangjiang.eshop.order.price.v1.calculator.TotalPriceCalculator;
import com.jiangjiang.eshop.order.price.v1.factory.*;
import com.jiangjiang.eshop.order.service.OrderInfoService;
import com.jiangjiang.eshop.order.service.OrderItemService;
import com.jiangjiang.eshop.order.service.ReturnGoodsApplyService;
import com.jiangjiang.eshop.order.status.LoggedOrderStateManager;
import com.jiangjiang.eshop.pay.service.PayService;
import com.jiangjiang.eshop.promotion.dto.PromotionActivityDTO;
import com.jiangjiang.eshop.promotion.service.PromotionFacadeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * @ClassName OrderInfoBiz
 * @Description TODO
 * @Author jhw
 * @Date 2021/7/24 11:37
 * @Version 1.0
 **/
@Service
public class OrderInfoBiz {
    @Autowired
    private PromotionFacadeService promotionFacadeService;
    @Autowired
    private DefaultOrderPriceCalculatorFactory defaultOrderPriceCalculatorFactory;
    @Autowired
    private GiftOrderPriceCalculatorFactory giftOrderPriceCalculatorFactory;
    @Autowired
    private DiscountOrderPriceCalculatorFactory discountOrderPriceCalculatorFactory;
    @Autowired
    private CouponCalculatorFactory couponCalculatorFactory;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private LoggedOrderStateManager orderStateManager;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private PayService payService;
    @Autowired
    private CustomerFacadeService customerFacadeService;
    @Autowired
    private ReturnGoodsApplyService returnGoodsApplyService;

    /**
     * 计算订单价格
     *
     * @param orderInfo 订单
     * @return 订单
     */
    public OrderInfoDTO calculateOrderPrice(OrderInfoDTO orderInfo) throws Exception {
        // 定义订单的各种价格
        Double totalAmount = 0.0;
        Double discountAmount = 0.0;
        Double freight = 0.0;
        List<OrderItemDTO> giftOrderItems = new ArrayList<OrderItemDTO>();

        for (OrderItemDTO orderItem : orderInfo.getOrderItems()) {
            PromotionActivityDTO dto = promotionFacadeService.queryById(orderItem.getPromotionActivityId());
            OrderPriceCalculatorFactory factory = getPriceCalculatorFactory(dto);
            FreightCalculator freightCalculator = factory.createFreightCalculator();
            PromotionActivityCalculator promotionActivityCalculator = factory.createPromotionActivityCalculator(dto);
            TotalPriceCalculator totalPriceCalculator = factory.createTotalPriceCalculator();
            // 汇总订单总金额
            totalAmount += totalPriceCalculator.calculate(orderItem);
            PromotionActivityResult result = promotionActivityCalculator.calculate(orderItem, dto);
            //汇总促销活动优惠
            discountAmount += result.getDiscountAmount();
            // 处理赠品
            giftOrderItems.addAll(result.getOrderItems());
            // 汇总运费
            freight += freightCalculator.calculate(orderInfo, orderItem, result);

        }
        // 给订单设置计算后的结果（同时已经包含了所有的赠品）
        orderInfo.setTotalAmount(totalAmount);
        orderInfo.setDiscountAmount(discountAmount);
        orderInfo.setFreight(freight);
        // 计算优惠券金额
        orderInfo.setPayableAmount(totalAmount + freight - discountAmount);
        orderInfo.getOrderItems().addAll(giftOrderItems);
        return orderInfo;
    }

    /**
     * 获取价格计算的工厂
     *
     * @param dto 营销活动
     * @return
     */
    private OrderPriceCalculatorFactory getPriceCalculatorFactory(PromotionActivityDTO dto) {
        if (Objects.isNull(dto)) {
            return defaultOrderPriceCalculatorFactory;
        }

        if (PromotionActivityType.DIRECT_GIFT.equals(dto.getType()) || PromotionActivityType.REACH_GIFT.equals(dto.getType())) {
            return giftOrderPriceCalculatorFactory;
        } else {
            return discountOrderPriceCalculatorFactory;
        }
    }

    /**
     * 计算优惠券抵扣的金额
     *
     * @param orderInfo 订单信息
     * @param coupon    优惠券
     * @return 计算结果
     */
    public OrderInfoDTO calculateCouponDiscountPrice(OrderInfoDTO orderInfo, CouponDTO coupon) throws Exception {
        CouponCalculator couponCalculator = couponCalculatorFactory.create(coupon);
        Double couponAmount = couponCalculator.calculate(orderInfo, coupon);
        orderInfo.setCouponAmount(couponAmount);
        orderInfo.setPayableAmount(orderInfo.getPayableAmount() - couponAmount);
        return orderInfo;
    }


    /**
     * 确认订单
     *
     * @param orderInfo
     * @return
     * @throws Exception
     */
    public OrderInfoDTO confirmOrder(OrderInfoDTO order) throws Exception {
        saveOrder(order);
        // 使用状态模式
        orderStateManager.create(order);
        inventoryService.informSubmitOrderEvent(order);
        promotionFacadeService.useCoupon(order.getCouponId(), order.getUserAccountId());

        return order;

    }

    private void saveOrder(OrderInfoDTO orderInfo) {
        orderInfo.setOrderNo(generateOrderNo());
        orderInfo.setPublishedComment(PublishedComment.NO);
        orderInfo.setOrderStatus(OrderStatus.UNKNOWN);
        orderInfo.setId(orderInfoService.saveOrderInfo(orderInfo));
        orderItemService.saveOrderItems(orderInfo.getId(), orderInfo.getOrderItems());
    }

    /**
     * 生成随机的订单编号
     *
     * @return
     */
    private String generateOrderNo() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 订单取消
     *
     * @param id 订单id
     * @return 处理结果
     */
    public Boolean cancel(Long id) throws Exception {
        OrderInfoDTO order = orderInfoService.queryById(id);
        if (Objects.isNull(order)) {
            return false;
        }

        if (!orderStateManager.canCancel(order)) {
            return false;
        }

        orderStateManager.canCancel(order);
        inventoryService.informCancelOrderEvent(order);
        return true;
    }

    /**
     * 订单支付
     *
     * @param id 订单id
     * @return 支付二维码
     */
    public String pay(Long id) throws Exception {
        OrderInfoDTO order = orderInfoService.queryById(id);
        if (!orderStateManager.canPay(order)) {
            return null;
        }
        return payService.getQrCode(order);
    }


    /**
     * 手动确认收获
     *
     * @param orderInfoId 订单id
     * @return 处理结果
     */
    public Boolean manualConfirmReceipt(Long orderInfoId) throws Exception {
        OrderInfoDTO order = orderInfoService.queryById(orderInfoId);
        if (!orderStateManager.canConfirmReceipt(order)) {
            return false;
        }
        // 状态变更并且记录日志
        // 此处不补充记录确认收获时间的原因是：更新状态时会自动补充
        orderStateManager.confirmReceipt(order);
        return true;
    }


    /**
     * 申请退货
     *
     * @param dto 退货申请
     * @return 处理结果
     */
    public Boolean applyReturnGoods(ReturnGoodsApplyDTO dto) throws Exception {
        OrderInfoDTO order = orderInfoService.queryById(dto.getOrderInfoId());
        if (!orderStateManager.canApplyReturnGoods(order)) {
            return false;
        }
        // 保存退货申请记录
        returnGoodsApplyService.save(dto);
        // 变更订单状态并记录操作日志
        orderStateManager.applyReturnGoods(order);
        // 创建退货工单
        customerFacadeService.createReturnGoodsWorksheet(
                order.getId(),
                order.getOrderNo(),
                dto.getReturnGoodsReason(),
                dto.getReturnGoodsComment()
        );
        return true;

    }


    /**
     * 更新退货物流单号
     *
     * @param orderInfoId             订单id
     * @param returnGoodsLogisticCode 退货物流单号
     * @throws Exception
     */
    public Boolean updateReturnGoodsLogisticCode(Long orderInfoId, String returnGoodsLogisticCode) throws Exception {
        OrderInfoDTO order = orderInfoService.queryById(orderInfoId);

        // 更新退货物流单号
        returnGoodsApplyService.updateReturnGoodsLogisticCode(orderInfoId, returnGoodsLogisticCode);
        // 同步物流单号到退货工单
        customerFacadeService.syncReturnGoodsLogisticsCode(orderInfoId, returnGoodsLogisticCode);
        // 变更订单状态
        orderStateManager.sendOutReturnGoods(order);
        return true;
    }
}
